suite("editor", function () {
    "use strict";

    var editor = require("./editor");
    var assert = require("assert");

    test("layout selector syncs layouts", function () {
        var doc = require("./document");
        var Node = require("./document-node");

        var layouts = new Node.List([
            new doc.Layout(0, 0),
            new doc.Layout(1, 0),
            new doc.Layout(2, 0)
        ]);

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                selector: {}
            }
        };

        var layoutSelector = new editor.LayoutSelector(view, "selector", layouts);
        assert(view.props.selector.items.length === 3);

        layouts.append(new doc.Layout(3, 0));
        assert(view.props.selector.items.length === 4);
    });

    test("layout selector syncs selected item", function () {
        var doc = require("./document");
        var Node = require("./document-node");

        var item = new doc.Layout(0, 0);
        var layouts = new Node.List([
            item,
            new doc.Layout(1, 0),
            new doc.Layout(2, 0)
        ]);

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                selector: {}
            }
        };

        var layoutSelector = new editor.LayoutSelector(view, "selector", layouts);

        layoutSelector.selectedLayout = item;
        assert(view.props.selector.selectedIndex === 0);

        layouts.setItems([
            new doc.Layout(3, 0),
            item
        ]);
        assert(view.props.selector.selectedIndex === 1);

        layouts.remove(item);
        assert(layoutSelector.selectedLayout === null);
        assert(view.props.selector.selectedIndex === -1);
    });

    test("layout selector creates new layout on request", function () {
        var doc = require("./document");
        var Node = require("./document-node");

        var layouts = new Node.List([
            new doc.Layout(0, 0),
            new doc.Layout(1, 0),
            new doc.Layout(2, 0)
        ]);

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                selector: {}
            }
        };

        var layoutSelector = new editor.LayoutSelector(view, "selector", layouts);

        view.props.selector.onRequestNew();
        assert(layouts.items.length === 4);
        assert(layoutSelector.selectedLayout === layouts.items[3]);
    });

    test("layout selector selects item on request", function () {
        var doc = require("./document");
        var Node = require("./document-node");

        var layouts = new Node.List([
            new doc.Layout(0, 0),
            new doc.Layout(1, 0),
            new doc.Layout(2, 0)
        ]);

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                selector: {}
            }
        };

        var layoutSelector = new editor.LayoutSelector(view, "selector", layouts);

        view.props.selector.onSelect({index: 1});
        assert(layoutSelector.selectedLayout === layouts.items[1]);
    });

    test("layout editor channels view delete event", function () {

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                layout: {}
            }
        };

        var layoutEditor = new editor.LayoutEditor(view, "layout");
        var called = false;
        layoutEditor.on("delete", function () {
            called = true;
        });

        view.props.layout.onDelete();
        assert(called);
    });

    test("layout editor sets view visibility", function () {
        var doc = require("./document");

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                layout: {}
            }
        };

        var layoutEditor = new editor.LayoutEditor(view, "layout");
        layoutEditor.layout = new doc.Layout(0, 0);
        assert(view.props.layout.visible);

        layoutEditor.layout = null;
        assert(!view.props.layout.visible);
    });

    test("document editor sets edited layout on selected layout change", function () {
        var doc = require("./document");

        var editorDoc = new doc.Document(0, 0);

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                "template-selector": {},
                "page-selector": {},
                "layout-editor": {}
            }
        };

        var documentEditor = new editor.DocumentEditor(view, "", editorDoc);

        var layout = new doc.Layout(0, 0);
        documentEditor.pageSelector.selectedLayout = layout;
        assert(documentEditor.layoutEditor.layout === layout, "to layout");

        documentEditor.pageSelector.selectedLayout = null;
        assert(documentEditor.layoutEditor.layout === null, "to null");
    });

    test("deletes layout on request", function () {
        var doc = require("./document");

        var editorDoc = new doc.Document(0, 0);

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                "template-selector": {},
                "page-selector": {},
                "layout-editor": {}
            }
        };

        var documentEditor = new editor.DocumentEditor(view, "", editorDoc);

        editorDoc.pages.append(new doc.Layout(1, 0));
        editorDoc.pages.append(new doc.Layout(2, 0));
        editorDoc.pages.append(new doc.Layout(3, 0));

        documentEditor.pageSelector.selectedLayout = editorDoc.pages.items[0];
        documentEditor.layoutEditor.trigger("delete");
        assert(editorDoc.pages.items.length === 2);
    });

    test("two editors preserve selection on deleting different one", function () {
        var doc = require("./document");
        var Sync = require("./document-sync");
        var node = require("./document-node");
        var view = require("./view.jsx");

        var editorDoc = node.create(doc.Document);
        editorDoc.pages.append(node.create(doc.Layout));
        editorDoc.pages.append(node.create(doc.Layout));

        var documentSync = new Sync(editorDoc, localStorage);
        editorDoc.version++;

        var el = document.createElement("div");
        document.body.appendChild(el);
        var documentEditor0 = new editor.DocumentEditor(
            view.createDocument(el), "",
            new doc.Document(editorDoc.id, 0));

        el = document.createElement("div");
        document.body.appendChild(el);
        var documentEditor1 = new editor.DocumentEditor(
            view.createDocument(el), "",
            new doc.Document(editorDoc.id, 0));

        documentEditor0.pageSelector.selectedLayout = documentEditor0.document.pages.items[1];
        documentEditor1.pageSelector.selectedLayout = documentEditor1.document.pages.items[0];

        documentEditor0.deleteLayout();
        documentEditor0.sync.load();
        documentEditor1.sync.load();
        assert(documentEditor0.document.pages.items.length === 1);
        assert(documentEditor1.document.pages.items.length === 1);
        assert(documentEditor1.pageSelector.selectedLayout === documentEditor1.document.pages.items[0]);
        assert(documentEditor1.layoutEditor.layout === documentEditor1.document.pages.items[0]);
    });

    test("selector changes position of layouts, only if indexes are different", function () {
        var doc = require("./document");
        var Node = require("./document-node");

        var layouts = new Node.List();

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                selector: {}
            }
        };

        var layoutSelector = new editor.LayoutSelector(view, "selector", layouts);

        layouts.splice = function () {
            assert(false);
        };
        view.props.selector.onPosition({newIndex: 1, oldIndex: 1});
    });

    test("selector changes position of layouts", function () {
        var doc = require("./document");
        var Node = require("./document-node");

        var layouts = new Node.List([{
            id: 0
        }, {
            id: 1
        }, {
            id: 2
        }]);

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            },
            refs: {
                selector: {}
            }
        };

        var layoutSelector = new editor.LayoutSelector(view, "selector", layouts);
        view.props.selector.onPosition({newIndex: 1, oldIndex: 2});
        assert(layouts.items[0].id === 0);
        assert(layouts.items[1].id === 2);
        assert(layouts.items[2].id === 1);
    });

    test("layout editor creates new block, only when has layout set", function () {
        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            }
        };
        var layout = new editor.LayoutEditor(view, "layout");
        view.props.layout.onNewBlock();
    });

    test("layout editor creates new block, only when valid type is requested", function () {
        var doc = require("./document");

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            }
        };

        var layout = new editor.LayoutEditor(view, "layout");
        layout.layout = new doc.Layout(0, 0);
        view.props.layout.onNewBlock({type: "some type"});
        assert(layout.layout.blocks.items.length === 0);
    });

    test("layout editor creates new block when requested", function () {
        var doc = require("./document");

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            }
        };

        var layout = new editor.LayoutEditor(view, "layout");
        layout.layout = new doc.Layout(0, 0);
        view.props.layout.onNewBlock({
            type: "text",
            x: 3,
            y: 4
        });

        assert(layout.layout.blocks.items.length === 1);
        assert(layout.layout.blocks.items[0] instanceof doc.TextBlock);
        assert(layout.layout.blocks.items[0].position.x === 3);
        assert(layout.layout.blocks.items[0].position.y === 4);
    });

    test("editor doesn't update view when view frozen", function () {
        var Node = require("./document-node");
        var doc = require("./document");

        var view = {
            props: {},
            setProps: function () {}
        };

        var selector = new editor.LayoutSelector(view, "selector", new Node.List);
        view.setProps = function () {
            assert(false);
        };
        selector.viewFrozen = true;
        selector.layouts.append(new doc.Layout(0, 0));
    });

    test("layout editor creates new block with the highest zIndex", function () {
        var doc = require("./document");

        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            }
        };

        var layout = new editor.LayoutEditor(view, "layout");
        layout.layout = new doc.Layout(0, 0);
        layout.layout.blocks.append(new doc.TextBlock(1, 0));
        layout.layout.blocks.append(new doc.TextBlock(2, 0));
        layout.layout.blocks.items[0].zIndex = 4;
        layout.layout.blocks.items[1].zIndex = 2;
        view.props.layout.onNewBlock({
            type: "text",
            x: 3,
            y: 4
        });

        assert(layout.layout.blocks.items[0].zIndex === 1);
        assert(layout.layout.blocks.items[1].zIndex === 0);
        assert(layout.layout.blocks.items[2].zIndex === 2);
        assert(layout.layout.blocks.items[2].position.x === 3);
        assert(layout.layout.blocks.items[2].position.y === 4);
    });

    test("layout selector updates view on block change", function () {
        var Node = require("./document-node");
        var doc = require("./document");
        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            }
        };
        var layouts = new Node.List;
        layouts.append(new doc.Layout(0, 0));
        layouts.items[0].blocks.append(new doc.TextBlock(1, 0));
        var selector = new editor.LayoutSelector(view, "selector", layouts);
        layouts.items[0].blocks.items[0].position = {
            x: 0.6,
            y: 0.6
        };
        assert(view.props.selector.items[0].blocks[0].position.x === 0.6);
    });

    test("layout editor updates block on block move, only when move finished", function () {
        var doc = require("./document");
        var view = {
            props: {},
            setProps: function () {}
        };
        var layout = new doc.Layout(0, 0);
        layout.blocks.append(new doc.TextBlock(1, 0));
        layout.blocks.items[0].position = {
            x: 0.3,
            y: 0.4
        };
        var layoutEditor = new editor.LayoutEditor(view, "layout");
        layoutEditor.layout = layout;
        layoutEditor.onBlockMove({
            moving: true,
            blockId: 1,
            x: 0.6,
            y: 0,
            zIndex: 1
        });
        assert(layout.blocks.items[0].position.x === 0.3);
    });

    test("layout editor updates block on block move", function () {
        var doc = require("./document");
        var view = {
            props: {},
            setProps: function () {}
        };
        var layout = new doc.Layout(0, 0);
        layout.blocks.append(new doc.TextBlock(1, 0));
        layout.blocks.items[0].position = {
            x: 0.3,
            y: 0.4
        };
        var layoutEditor = new editor.LayoutEditor(view, "layout");
        layoutEditor.layout = layout;
        layoutEditor.onBlockMove({
            moving: false,
            blockId: 1,
            x: 0.6,
            y: 0,
            zIndex: 1
        });
        assert(layout.blocks.items[0].position.x === 0.6);
    });

    test("layout editor updates displayed blocks on block change", function () {
        var doc = require("./document");
        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            }
        };
        var layout = new doc.Layout(0, 0);
        layout.blocks.append(new doc.TextBlock(1, 0));
        layout.blocks.items[0].position = {
            x: 0.3,
            y: 0.4
        };
        var layoutEditor = new editor.LayoutEditor(view, "layout");
        layoutEditor.layout = layout;
        layout.blocks.items[0].position = {
            x: 0.6,
            y: 0
        };
        assert(view.props.layout.blocks[0].position.x === 0.6);
    });

    test("layout editor resizes block, only when resize complete", function () {
        var doc = require("./document");
        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
            }
        };
        var layout = new doc.Layout(0, 0);
        layout.blocks.append(new doc.TextBlock(1, 0));
        layout.blocks.items[0].size = {
            width: 0.3,
            height: 0.4
        };
        var layoutEditor = new editor.LayoutEditor(view, "layout");
        layoutEditor.layout = layout;
        view.props.layout.onBlockResize({
            moving: true,
            x: 0,
            y: 0,
            width: 0.45,
            height: 0.45
        });
        assert(layout.blocks.items[0].size.width === 0.3);
    });

    test("layout editor moves and resizes the block view in one step", function () {
        var doc = require("./document");
        var called = 0;
        var view = {
            props: {},
            setProps: function (props) {
                this.props = props;
                called++;
            }
        };

        var layout = new doc.Layout(0, 0);
        layout.blocks.append(new doc.TextBlock(1, 0));
        layout.blocks.items[0].position = {
            x: 0.24,
            y: 0.24
        };
        layout.blocks.items[0].size = {
            width: 0.3,
            height: 0.3
        };
        var layoutEditor = new editor.LayoutEditor(view, "layout");
        layoutEditor.layout = layout;
        called = 0;
        view.props.layout.onBlockResize({
            moving: false,
            blockId: 1,
            x: 0.45,
            y: 0.45,
            width: 0.54,
            height: 0.54
        });
        assert(called === 2);
    });
});
